import dayjs from "dayjs";
import { createI18n, type I18n } from "vue-i18n";
import type { App } from "vue";
import type { Language } from "element-plus/es/locale";
import zhCn from "element-plus/dist/locale/zh-cn.mjs";
import en from "element-plus/dist/locale/en.mjs";
import { type LanguageType, LANGUAGE } from "@/constants/enums";
import { useOptionsStore } from "@/store/modules/options";

type Message = {
  [key: string]: Message | string;
};

type I18nMessage = Record<LanguageType, Message>;

interface LocaleFile {
  default: Message;
}

const elementLocale = ref<Language>(zhCn);
let i18n: I18n<{}, {}, {}, string, false>;

async function loadMessage(loadLang: LanguageType): Promise<I18nMessage> {
  const modules = import.meta.glob("@/locales/langs/*/*.json");
  const message: I18nMessage = {
    "en-US": {},
    "zh-CN": {},
  };
  const reg = /.*?langs\/(?<lang>.*?)\/(?<fileName>.*?).json/;

  const loadPromises = Object.entries(modules).map(async ([pathStr, moduleJson]) => {
    let found = pathStr.match(reg);
    if (found?.groups) {
      let lang: LanguageType = found.groups["lang"] as LanguageType;
      let fileName: LanguageType = found.groups["fileName"] as LanguageType;
      if (loadLang !== lang) return;
      try {
        const { default: jsonData } = (await moduleJson()) as LocaleFile;
        if (message[lang]) {
          (message[lang] as Message)[fileName] = jsonData;
        } else {
          message[lang] = { [fileName]: jsonData };
        }
      } catch (error) {
        console.error(`locale ${fileName}.json loading error: `, error);
      }
    }
  });
  await Promise.all(loadPromises);
  i18n?.global.setLocaleMessage(loadLang, message[loadLang]);
  return message;
}

async function loadDayjsLocale(lang: LanguageType) {
  switch (lang) {
    case LANGUAGE.ZH:
      await import("dayjs/locale/zh-cn");
      dayjs.locale("zh-cn");
      break;
    case LANGUAGE.EN:
      dayjs.locale("en");
      break;
    default:
      dayjs.locale("en");
  }
}

async function loadElementLocale(lang: LanguageType) {
  switch (lang) {
    case LANGUAGE.ZH:
      elementLocale.value = zhCn;
      break;
    case LANGUAGE.EN:
      elementLocale.value = en;
      break;
    default:
  }
}

async function loadThirdLocale(lang: LanguageType) {
  await Promise.all([loadDayjsLocale(lang), loadElementLocale(lang)]);
}

async function switchLanguage(lang: LanguageType = LANGUAGE.ZH) {
  await Promise.all([(loadThirdLocale(lang), loadMessage(lang))]);
  i18n.global.locale.value = lang; // i18n language setting
  const optionsStore = useOptionsStore();
  optionsStore.settingLocale(lang);
}

const setupI18n = async (app: App) => {
  const optionsStore = useOptionsStore();
  let locale = optionsStore.locale;
  const messages = await loadMessage(locale);
  i18n = createI18n({
    legacy: false,
    locale,
    fallbackLocale: LANGUAGE.EN,
    messages,
  });
  await loadThirdLocale(locale);
  // await Promise.all([loadThirdLocale(locale), loadMessage(locale)]);
  app.use(i18n);
};

export { setupI18n, elementLocale, switchLanguage };
